Tagged Unions

A tagged union declaration looks just like a C union, except that it you must specify the @tagged qualifier when declaring it. For example:

   @tagged union Foo {
      int i;
      double d;
      char *@fat s;
   };

The primary difference with C unions is that a tagged union includes a hidden tag. The tag indicates which member was last written. So, for example:

  union Foo x;
  x.i = 3;
  x.s = "hello";

causes the hidden tag to first indicate that the i member was written, and then is updated to record that the s member was written.

When you attempt to read a member of a tagged union, a check is done on the hidden tag to ensure that this was the last member written, and thus the union contains a valid object of that member’s type. If some other member was last updated, then a Match_Exception will be thrown.

You can test the hidden tag of a tagged union by using the tagcheck operation. For example:

  void printFoo(union Foo x) {
    if (tagcheck(x.i))
      printf("%d",x.i);
    else if (tagcheck(x.d))
      printf("%g",x.d);
    else if (tagcheck(x.s))
      printf("%s",x.s);
  }

Alternatively, you can use pattern matching (described in the next section) which will ensure that you cover all of the cases properly. For instance, the function above may be rewritten as:

  void printFoo(union Foo x) {
    switch (x) {
    case {.i = i}: printf("%d",i); break;
    case {.d = d}: printf("%g",d); break;
    case {.s = s}: printf("%s",s); break;
    }
  }

If we failed to leave out one of the cases in the pattern match, then the compiler would warn us. This is particularly helpful when you add new variants to a tagged union, for then the compiler pinpoints the spots that you need to update in your code. Therefore, we encourage the use of pattern matching where possible.